﻿using System.ComponentModel.DataAnnotations;
using TDMS.Net.Internals;

namespace TDMS.Net;

using static NiLibDDC;

public class TdmsProperty
{
    public IntPtr Owner { get; }

    public ETdmsPropertyOwnerType OwnerType { get; }

    public object Value { get; }

    public string Name { get; }

    public ETdmsPropertyDataType DataType { get; }

    public TdmsProperty(IntPtr owner, ETdmsPropertyOwnerType ownerType, string name, ETdmsPropertyDataType dataType, object value)
    {
        Name = name;
        Owner = owner;
        OwnerType = ownerType;
        Value = value;
        DataType = dataType;

        Validate(value, dataType);
        Create();
    }

    private void Validate(object value) => Validate(value, DataType);

    private void Validate(object value, ETdmsPropertyDataType dataType)
    {
        var expectType = dataType switch
        {
            ETdmsPropertyDataType.UInt8 => typeof(byte),
            ETdmsPropertyDataType.Int16 => typeof(short),
            ETdmsPropertyDataType.Int32 => typeof(int),
            ETdmsPropertyDataType.Float => typeof(float),
            ETdmsPropertyDataType.Double => typeof(double),
            ETdmsPropertyDataType.String => typeof(string),
            ETdmsPropertyDataType.DateTime => typeof(DateTime),
            _ => throw new TdmsException("Not supported")
        };

        if (value.GetType() != expectType)
        {
            ExceptionBuilder.ThrowPropertyDataTypeMismatch(Name);
        }
    }

    private void Create()
    {
        switch (DataType)
        {
            case ETdmsPropertyDataType.UInt8:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateFilePropertyUInt8(Owner, Name, (byte)Value));
                        return;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelGroupPropertyUInt8(Owner, Name, (byte)Value));
                        return;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelPropertyUInt8(Owner, Name, (byte)Value));
                        return;
                }
                break;
            case ETdmsPropertyDataType.Int16:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateFilePropertyInt16(Owner, Name, (short)Value));
                        return;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelGroupPropertyInt16(Owner, Name, (short)Value));
                        return;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelPropertyInt16(Owner, Name, (short)Value));
                        return;
                }
                break;
            case ETdmsPropertyDataType.Int32:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateFilePropertyInt32(Owner, Name, (int)Value));
                        return;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelGroupPropertyInt32(Owner, Name, (int)Value));
                        return;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelPropertyInt32(Owner, Name, (int)Value));
                        return;
                }
                break;
            case ETdmsPropertyDataType.Float:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateFilePropertyFloat(Owner, Name, (float)Value));
                        return;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelGroupPropertyFloat(Owner, Name, (float)Value));
                        return;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelPropertyFloat(Owner, Name, (float)Value));
                        return;
                }
                break;
            case ETdmsPropertyDataType.Double:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateFilePropertyDouble(Owner, Name, (double)Value));
                        return;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelGroupPropertyDouble(Owner, Name, (double)Value));
                        return;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelPropertyDouble(Owner, Name, (double)Value));
                        return;
                }
                break;
            case ETdmsPropertyDataType.String:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateFilePropertyString(Owner, Name, (string)Value));
                        return;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelGroupPropertyString(Owner, Name, (string)Value));
                        return;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelPropertyString(Owner, Name, (string)Value));
                        return;
                }
                break;
            case ETdmsPropertyDataType.DateTime:
                var time = (DateTime)Value;
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateFilePropertyTimestampComponents(Owner, Name, (uint)time.Year, (uint)time.Month, (uint)time.Day, (uint)time.Hour, (uint)time.Minute, (uint)time.Second, (double)time.Millisecond));
                        return;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelGroupPropertyTimestampComponents(Owner, Name, (uint)time.Year, (uint)time.Month, (uint)time.Day, (uint)time.Hour, (uint)time.Minute, (uint)time.Second, (double)time.Millisecond));
                        return;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_CreateChannelPropertyTimestampComponents(Owner, Name, (uint)time.Year, (uint)time.Month, (uint)time.Day, (uint)time.Hour, (uint)time.Minute, (uint)time.Second, (double)time.Millisecond));
                        return;
                }
                break;
            default:
                throw new TdmsException("Not supported");
        }
    }

    public TdmsProperty Set(object value)
    {
        Validate(value);

        switch (DataType)
        {
            case ETdmsPropertyDataType.UInt8:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_SetFilePropertyUInt8(Owner, Name, (byte)Value));
                        break;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelGroupPropertyUInt8(Owner, Name, (byte)Value));
                        break;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelPropertyUInt8(Owner, Name, (byte)Value));
                        break;
                }
                break;
            case ETdmsPropertyDataType.Int16:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_SetFilePropertyInt16(Owner, Name, (short)Value));
                        break;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelGroupPropertyInt16(Owner, Name, (short)Value));
                        break;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelPropertyInt16(Owner, Name, (short)Value));
                        break;
                }
                break;
            case ETdmsPropertyDataType.Int32:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_SetFilePropertyInt32(Owner, Name, (int)Value));
                        break;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelGroupPropertyInt32(Owner, Name, (int)Value));
                        break;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelPropertyInt32(Owner, Name, (int)Value));
                        break;
                }
                break;
            case ETdmsPropertyDataType.Float:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_SetFilePropertyFloat(Owner, Name, (float)Value));
                        break;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelGroupPropertyFloat(Owner, Name, (float)Value));
                        break;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelPropertyFloat(Owner, Name, (float)Value));
                        break;
                }
                break;
            case ETdmsPropertyDataType.Double:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_SetFilePropertyDouble(Owner, Name, (double)Value));
                        break;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelGroupPropertyDouble(Owner, Name, (double)Value));
                        break;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelPropertyDouble(Owner, Name, (double)Value));
                        break;
                }
                break;
            case ETdmsPropertyDataType.String:
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_SetFilePropertyString(Owner, Name, (string)Value));
                        break;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelGroupPropertyString(Owner, Name, (string)Value));
                        break;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelPropertyString(Owner, Name, (string)Value));
                        break;
                }
                break;
            case ETdmsPropertyDataType.DateTime:
                var time = (DateTime)Value;
                switch (OwnerType)
                {
                    case ETdmsPropertyOwnerType.File:
                        ExceptionBuilder.CheckApiStatus(DDC_SetFilePropertyTimestampComponents(Owner, Name, (uint)time.Year, (uint)time.Month, (uint)time.Day, (uint)time.Hour, (uint)time.Minute, (uint)time.Second, (uint)time.Millisecond));
                        break;
                    case ETdmsPropertyOwnerType.ChannelGroup:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelGroupPropertyTimestampComponents(Owner, Name, (uint)time.Year, (uint)time.Month, (uint)time.Day, (uint)time.Hour, (uint)time.Minute, (uint)time.Second, (uint)time.Millisecond));
                        break;
                    case ETdmsPropertyOwnerType.Channel:
                        ExceptionBuilder.CheckApiStatus(DDC_SetChannelPropertyTimestampComponents(Owner, Name, (uint)time.Year, (uint)time.Month, (uint)time.Day, (uint)time.Hour, (uint)time.Minute, (uint)time.Second, (uint)time.Millisecond));
                        break;
                }
                break;
            default:
                throw new TdmsException("Not supported");
        }

        return this;
    }
}

